#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
完整的图片爬取、上传和数据库更新脚本
功能：
1. 爬取真实的按摩、SPA、技师、服务图片
2. 上传到MinIO存储
3. 更新MySQL数据库
4. 提供图片URL给前端
"""
import os
import sys
import django
import requests
import time
from io import BytesIO
from PIL import Image

# 设置Django环境
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, BASE_DIR)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'massage_app.settings')
django.setup()

# 导入工具和模型
from tools.minio_client import minio_client
from services.models import Banner, Category, Technician, Service

# 设置UTF-8编码输出
if sys.platform == 'win32':
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')


class ImageCrawler:
    """图片爬虫类"""
    
    def __init__(self):
        self.minio = minio_client
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        }
        
    def download_image(self, url, timeout=10):
        """下载图片"""
        try:
            response = requests.get(url, headers=self.headers, timeout=timeout)
            if response.status_code == 200:
                return response.content
            else:
                print(f"  [警告] 下载失败，状态码: {response.status_code}")
                return None
        except Exception as e:
            print(f"  [错误] 下载图片失败: {e}")
            return None
    
    def resize_image(self, image_bytes, size=(800, 600)):
        """调整图片大小"""
        try:
            img = Image.open(BytesIO(image_bytes))
            img = img.convert('RGB')  # 确保是RGB模式
            img.thumbnail(size, Image.Resampling.LANCZOS)
            
            output = BytesIO()
            img.save(output, format='JPEG', quality=85)
            return output.getvalue()
        except Exception as e:
            print(f"  [错误] 调整图片大小失败: {e}")
            return image_bytes
    
    def upload_to_minio(self, image_bytes, object_name, content_type='image/jpeg'):
        """上传图片到MinIO"""
        try:
            self.minio.upload_bytes(object_name, image_bytes, content_type=content_type)
            # 生成公开访问URL
            # MinIO客户端配置endpoint
            from tools.minio_client import endpoint
            url = f"http://{endpoint}/{self.minio.bucket_name}/{object_name}"
            return url
        except Exception as e:
            print(f"  [错误] 上传到MinIO失败: {e}")
            import traceback
            print(traceback.format_exc())
            return None


def get_image_urls():
    """
    获取真实图片URL
    使用免费图片服务API（不需要密钥）
    """
    image_urls = {
        'banners': [
            'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=1200&h=600&fit=crop',  # 按摩场景
            'https://images.unsplash.com/photo-1540555700478-4be289fbecef?w=1200&h=600&fit=crop',  # SPA场景
            'https://images.unsplash.com/photo-1519823551278-64ac92734fb1?w=1200&h=600&fit=crop',  # 足疗场景
        ],
        'categories': {
            'massage': 'https://images.unsplash.com/photo-1519823551278-64ac92734fb1?w=200&h=200&fit=crop',
            'spa': 'https://images.unsplash.com/photo-1540555700478-4be289fbecef?w=200&h=200&fit=crop',
            'footcare': 'https://images.unsplash.com/photo-1598971639058-fab3c3109a00?w=200&h=200&fit=crop',
            'bodycare': 'https://images.unsplash.com/photo-1515377905703-c4788e51af15?w=200&h=200&fit=crop',
        },
        'technicians': [
            'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=300&h=300&fit=crop',  # 女技师
            'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=300&h=300&fit=crop',  # 男技师
            'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=300&h=300&fit=crop',  # 女技师
        ],
        'services': [
            'https://images.unsplash.com/photo-1544161515-4ab6ce6db874?w=600&h=400&fit=crop',  # 全身按摩
            'https://images.unsplash.com/photo-1598971639058-fab3c3109a00?w=600&h=400&fit=crop',  # 足疗
            'https://images.unsplash.com/photo-1540555700478-4be289fbecef?w=600&h=400&fit=crop',  # SPA
        ]
    }
    return image_urls


def crawl_and_upload_banners(crawler):
    """爬取并上传轮播图"""
    print("\n[1/4] 处理轮播图...")
    
    urls = get_image_urls()['banners']
    banners = Banner.objects.filter(is_active=True).order_by('sort_order')[:len(urls)]
    
    for idx, (banner, image_url) in enumerate(zip(banners, urls)):
        print(f"\n  处理轮播图 [{idx+1}/{len(urls)}]: {banner.title}")
        
        # 下载图片
        print(f"    - 下载图片...")
        image_bytes = crawler.download_image(image_url)
        if not image_bytes:
            continue
        
        # 调整大小
        print(f"    - 调整图片大小...")
        resized_image = crawler.resize_image(image_bytes, size=(1200, 600))
        
        # 上传到MinIO
        object_name = f"banners/banner{idx+1}.jpg"
        print(f"    - 上传到MinIO: {object_name}")
        minio_url = crawler.upload_to_minio(resized_image, object_name)
        
        if minio_url:
            # 更新数据库
            banner.image = minio_url
            banner.save()
            print(f"    [成功] URL: {minio_url}")
        
        time.sleep(0.5)  # 避免请求过快


def crawl_and_upload_categories(crawler):
    """爬取并上传分类图标"""
    print("\n[2/4] 处理分类图标...")
    
    urls = get_image_urls()['categories']
    categories = Category.objects.filter(is_active=True).order_by('sort_order')
    
    for idx, category in enumerate(categories):
        category_name = category.name
        if category_name not in urls:
            continue
            
        print(f"\n  处理分类 [{idx+1}/{len(categories)}]: {category.get_name_display()}")
        
        # 下载图片
        print(f"    - 下载图片...")
        image_bytes = crawler.download_image(urls[category_name])
        if not image_bytes:
            continue
        
        # 调整大小
        print(f"    - 调整图片大小...")
        resized_image = crawler.resize_image(image_bytes, size=(200, 200))
        
        # 上传到MinIO
        object_name = f"categories/{category_name}.jpg"
        print(f"    - 上传到MinIO: {object_name}")
        minio_url = crawler.upload_to_minio(resized_image, object_name)
        
        if minio_url:
            # 更新数据库
            category.icon = minio_url
            category.save()
            print(f"    [成功] URL: {minio_url}")
        
        time.sleep(0.5)


def crawl_and_upload_technicians(crawler):
    """爬取并上传技师头像"""
    print("\n[3/4] 处理技师头像...")
    
    urls = get_image_urls()['technicians']
    technicians = Technician.objects.filter(is_active=True)[:len(urls)]
    
    for idx, (tech, image_url) in enumerate(zip(technicians, urls)):
        print(f"\n  处理技师 [{idx+1}/{len(urls)}]: {tech.name}")
        
        # 下载图片
        print(f"    - 下载图片...")
        image_bytes = crawler.download_image(image_url)
        if not image_bytes:
            continue
        
        # 调整大小
        print(f"    - 调整图片大小...")
        resized_image = crawler.resize_image(image_bytes, size=(300, 300))
        
        # 上传到MinIO
        object_name = f"technicians/tech{tech.id}.jpg"
        print(f"    - 上传到MinIO: {object_name}")
        minio_url = crawler.upload_to_minio(resized_image, object_name)
        
        if minio_url:
            # 更新数据库
            tech.avatar = minio_url
            tech.save()
            print(f"    [成功] URL: {minio_url}")
        
        time.sleep(0.5)


def crawl_and_upload_services(crawler):
    """爬取并上传服务图片"""
    print("\n[4/4] 处理服务图片...")
    
    urls = get_image_urls()['services']
    services = Service.objects.filter(is_active=True)[:len(urls)]
    
    for idx, (service, image_url) in enumerate(zip(services, urls)):
        print(f"\n  处理服务 [{idx+1}/{len(urls)}]: {service.name}")
        
        # 下载图片
        print(f"    - 下载图片...")
        image_bytes = crawler.download_image(image_url)
        if not image_bytes:
            continue
        
        # 调整大小
        print(f"    - 调整图片大小...")
        resized_image = crawler.resize_image(image_bytes, size=(600, 400))
        
        # 上传到MinIO
        object_name = f"services/service{service.id}.jpg"
        print(f"    - 上传到MinIO: {object_name}")
        minio_url = crawler.upload_to_minio(resized_image, object_name)
        
        if minio_url:
            # 更新数据库
            service.image = minio_url
            service.save()
            print(f"    [成功] URL: {minio_url}")
        
        time.sleep(0.5)


def main():
    """主函数"""
    print("=" * 70)
    print(" " * 15 + "图片爬取和上传工具")
    print("=" * 70)
    print("\n功能说明:")
    print("  1. 从Unsplash爬取真实的高质量图片")
    print("  2. 自动调整图片大小")
    print("  3. 上传到MinIO存储服务器")
    print("  4. 更新MySQL数据库图片URL")
    print("\nMinIO服务器: minapi.huaxianguan.com")
    print("数据库: SQLite (开发环境)")
    print("=" * 70)
    
    try:
        # 创建爬虫实例
        crawler = ImageCrawler()
        
        # 执行爬取和上传
        crawl_and_upload_banners(crawler)
        crawl_and_upload_categories(crawler)
        crawl_and_upload_technicians(crawler)
        crawl_and_upload_services(crawler)
        
        # 显示统计
        print("\n" + "=" * 70)
        print(" " * 25 + "[完成]")
        print("=" * 70)
        
        print("\n[数据统计]")
        print(f"  - 轮播图: {Banner.objects.count()} 条")
        print(f"  - 分类图标: {Category.objects.count()} 条")
        print(f"  - 技师头像: {Technician.objects.count()} 条")
        print(f"  - 服务图片: {Service.objects.count()} 条")
        
        print("\n[下一步]")
        print("  1. 在浏览器访问: http://localhost:8000/api/services/app-images/")
        print("  2. 检查返回的JSON中的image字段是否为MinIO的URL")
        print("  3. 在小程序中刷新页面，查看新图片")
        print("  4. 图片示例URL格式:")
        print(f"     http://minapi.huaxianguan.com/anmo/banners/banner1.jpg")
        print()
        
    except Exception as e:
        print(f"\n[错误] 执行失败: {e}")
        import traceback
        print(traceback.format_exc())
        sys.exit(1)


if __name__ == '__main__':
    import sys
    
    # 检查是否有--yes参数跳过确认
    if '--yes' in sys.argv or '-y' in sys.argv:
        main()
    else:
        print("\n⚠️  警告: 此脚本将替换数据库中所有图片URL为MinIO地址")
        print("使用 --yes 或 -y 参数跳过此确认")
        print("\n运行命令: python scripts/crawl_and_upload_images.py --yes")
        sys.exit(0)

